package com.ehotting.edsta.circuitDesign.gen.element.helper;

import com.ehotting.edsta.circuitDesign.domain.EsElement;
import com.ehotting.edsta.circuitDesign.gen.ScriptConstants;

import java.util.*;
import java.util.stream.Collectors;


public class ElementResultComposeHelper {


    public final static Comparator comparator = new Comparator<Map<String,Object>>() {
        @Override
        public int compare(Map<String,Object> map1, Map<String,Object> map2) {
            Object o1= map1.get(ScriptConstants.DIFF);
            Object o2= map2.get(ScriptConstants.DIFF);
            if(o1==null && o2 == null)
                return 0;
            if(o1==null || !NumberHelper.isDouble(o1.toString()))
                return 1;
            if(o2==null || !NumberHelper.isDouble(o2.toString()))
                return 1;
            return NumberHelper.parseDouble(o1.toString())<NumberHelper.parseDouble(o2.toString())?-1:1;
        }
    };


    public static Map<String, EsElement> invoke(List<Map<String, Object>> componentInputList, List<String> allKeys){
        sort(componentInputList);

        List<Map<String, EsElement>> overMapList = invoke4List( componentInputList,  allKeys);
        if(overMapList!=null && overMapList.size()>0){
            return overMapList.get(0);
        }
        return null;
    }

    public static List<Map<String, Object>> sort(List<Map<String, Object>> overMapList){
       Collections.sort(overMapList,comparator);
       return overMapList;
    }

    public static List<Map<String, EsElement>> invoke4List(List<Map<String, Object>> componentInputList, List<String> allKeys){

        List<Map<String, EsElement>> list = ElementDataHelper.convertElement(componentInputList);

        List<Map<String, EsElement>> overMapList = findOver(list,  allKeys);
        if(overMapList.size()>0){
            return overMapList;
        }

        List<Map<String, EsElement>> resultList =  compose( list,  allKeys);
        if(resultList.size()>0){
            return resultList;
        }

        return null;
    }




    /**
     * 组合数据
     * @param allKeys
     * @param componentInputList
     * @return
     */
    public static List<Map<String, EsElement>> compose(List<Map<String, EsElement>> componentInputList, List<String> allKeys){

        List<Map<String, EsElement>> resultList = new ArrayList<>();

        for(int i=0;i<componentInputList.size();i++){
            Map<String, EsElement> mainMap = componentInputList.get(i);
            List<String> incompleteKeys = getIncompleteKeyList(mainMap, allKeys);
            fillMapValue(i, mainMap,  allKeys,  incompleteKeys,  componentInputList,resultList);
        }

        /**去重**/
        resultList =  resultList.stream().distinct().collect(Collectors.toList());

        return  resultList;
    }

    private static List<Map<String, EsElement>> findOver(List<Map<String, EsElement>> componentInputList, List<String> allKeys){
        List<Map<String, EsElement>> resultList = new ArrayList<>();
        for(Map<String, EsElement> map : componentInputList){
            List<String> incompleteKeys = getIncompleteKeyList(map, allKeys);
            if(incompleteKeys.size()==0){
                resultList.add(map);
            }
        }
        return resultList;
    }


    /***
     * 填充Map对象的值
     * @param index
     * @param mainMap
     * @param allKeys
     * @param incompleteKeys
     * @param componentInputList
     * @param resultList
     */
    private static void fillMapValue(int index, Map<String, EsElement> mainMap, List<String> allKeys, List<String> incompleteKeys, List<Map<String, EsElement>> componentInputList, List<Map<String, EsElement>> resultList){
        for(int i=index;i<componentInputList.size();i++){
            Map<String, EsElement> joinMap = componentInputList.get(i);
            if(isContainIncompleteKey(joinMap,incompleteKeys) && isJoinElement(mainMap , joinMap ,  allKeys) ){
                Map<String, EsElement> resultMap = fillValue(mainMap, joinMap , allKeys);
                if(!isCompleteKey(resultMap,  allKeys)){
                    /**resultMap不完整，继续填充**/
                    fillMapValue( index+1, resultMap,  allKeys,  incompleteKeys,  componentInputList,resultList);
                }else{
                    Map<String, EsElement> sortMap = sortMapKey( resultMap);
                    resultList.add(sortMap);
                    //System.out.println(JSON.toJSONString(sortMap));
                }
            }
        }

    }

    /***
     * 对Map.key进行排序
     * @param map
     * @return
     */
    private static Map<String, EsElement> sortMapKey(Map<String, EsElement> map){
        Map<String, EsElement> sortMap = map.entrySet().stream()
                .sorted(Map.Entry.comparingByKey())
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
                        (oldValue, newValue) -> oldValue, LinkedHashMap::new));
        return sortMap;
    }


    /**
     * 判断两个map是否可以组合，判断逻辑如下：
     * 如果关联key的值（使用id进行判断）都相等，那返回true
     * 如果关联key的值（使用id进行判断）存在一个不相等，那返回false
     * 如果没有关联key，那返回true
     *
     * @param joinMap
     * @param mainMan
     * @param allKeys
     * @return
     */
    private static boolean isJoinElement(Map<String, EsElement> mainMan , Map<String, EsElement> joinMap , List<String> allKeys){
        boolean flag = true;
        for(String key : allKeys){
            if(joinMap.containsKey(key) && mainMan.containsKey(key) ){
                if(joinMap.get(key).getId().equals(mainMan.get(key).getId())){
                    flag = true;
                }else{
                    flag = false;
                }
            }
        }
        return flag;
    }

    /**
     * 将joinMap从incompleteKeys找出，填主到cloneMap中
     * @param joinMap
     * @param mainMan
     * @param incompleteKeys
     * @return
     */
    private static Map<String, EsElement> fillValue(Map<String, EsElement> mainMan, Map<String, EsElement> joinMap , List<String> incompleteKeys){
        Map<String, EsElement> cloneMap = new HashMap<>(mainMan);
        for(String key : incompleteKeys){
            if(joinMap.containsKey(key) && !cloneMap.containsKey(key)){
                cloneMap.put(key,joinMap.get(key));

            }
        }
        return cloneMap;
    }


    /***
     * 判断joinMap中是否包含缺失key
     * @param joinMap
     * @param incompleteKeys
     * @return
     */
    private static boolean isContainIncompleteKey(Map<String, EsElement> joinMap, List<String> incompleteKeys){
        for(String key : incompleteKeys){
            if(joinMap.containsKey(key))
                return true;
        }
        return false;
    }


    /***
     * 从map中查找不完整的key
     * @param mainMap
     * @param allKeys
     * @return
     */
    private static List<String> getIncompleteKeyList(Map<String, ?> mainMap, List<String> allKeys){
        List<String> incompleteKeys = new ArrayList<>();
        for(String key : allKeys){
            if(!mainMap.containsKey(key))
                incompleteKeys.add(key);
        }
        return incompleteKeys;
    }

    /**
     * map是否完整key
     * @param map
     * @param allKeys
     * @return
     */
    private static boolean isCompleteKey(Map<String, EsElement> map, List<String> allKeys){
        boolean isAll = true;
        for(String key : allKeys){
            if(!map.containsKey(key))
                isAll = false;
        }
        return isAll;
    }
}